package com.dbms;

import com.dbms.common.QueryResult;
import java.io.File;

/**
 * 外键约束功能测试类
 * 功能：验证数据库中外键约束的正确性，包括：
 * 1. 插入操作时，子表外键必须引用父表已存在的主键
 * 2. 删除操作时，不允许删除被子表引用的父表记录
 *
 * 【已修复】
 * 1. 使用DbmsCore的专用构造函数，确保测试使用独立的数据库文件和日志文件，避免干扰其他测试
 * 2. 优化测试流程，更精确地验证外键删除约束的逻辑（先删子表记录才能删父表记录）
 */
public class ForeignKeyTest {

    // 测试专用数据库文件名：独立于其他测试，确保环境干净
    private static final String DB_FILE_NAME = "foreign_key_test.db";
    // 测试专用日志文件名：记录测试过程中的事务日志
    private static final String LOG_FILE_NAME = "foreign_key_test.log";

    /**
     * 测试主方法：执行外键约束的完整测试流程
     * @param args 命令行参数（未使用）
     */
    public static void main(String[] args) {
        System.out.println("============== Foreign Key Functionality Test Start ==============");

        // --- 1. 环境准备：清理旧文件，确保测试环境初始化 ---
        System.out.println("\n--- 1. Setup: Cleaning environment ---");
        // 删除旧的测试数据库文件和日志文件（若存在）
        new File(DB_FILE_NAME).delete();
        new File(LOG_FILE_NAME).delete();

        // 【核心修正】使用带文件名的构造函数初始化DbmsCore，确保测试使用独立文件
        DbmsCore dbms = new DbmsCore(DB_FILE_NAME, LOG_FILE_NAME);
        System.out.println("Test environment initialized.");

        // --- 2. 创建带外键约束的表结构 ---
        System.out.println("\n--- 2. Creating tables with foreign key constraint ---");
        // 创建父表departments（部门表）：主键为id
        String createParentTable = "CREATE TABLE departments (id INT PRIMARY KEY, name VARCHAR(50));";
        // 创建子表employees（员工表）：dept_id为外键，引用departments表的id
        String createChildTable = "CREATE TABLE employees (emp_id INT PRIMARY KEY, emp_name VARCHAR(50), dept_id INT, FOREIGN KEY (dept_id) REFERENCES departments(id));";

        // 执行创建父表SQL并打印结果
        System.out.println("--> " + createParentTable);
        printResult(dbms.processSql(createParentTable));
        // 执行创建子表SQL并打印结果
        System.out.println("--> " + createChildTable);
        printResult(dbms.processSql(createChildTable));
        System.out.println("✅ Tables created.");

        // --- 3. 测试插入操作中的外键约束 ---
        System.out.println("\n--- 3. Testing FOREIGN KEY on INSERT ---");
        // 测试1：插入子表记录时引用不存在的父表id（预期失败）
        System.out.println("--> (Expected to FAIL) Inserting an employee with a non-existent department ID (101).");
        printResult(dbms.processSql("INSERT INTO employees VALUES (1, 'John Doe', 101);"));

        // 测试2：插入父表记录（部门101）（预期成功）
        System.out.println("\n--> (Expected to SUCCEED) Inserting a department with ID 101.");
        printResult(dbms.processSql("INSERT INTO departments VALUES (101, 'Engineering');"));

        // 测试3：插入另一个父表记录（部门102）（预期成功）
        System.out.println("\n--> (Expected to SUCCEED) Inserting another department with ID 102.");
        printResult(dbms.processSql("INSERT INTO departments VALUES (102, 'Marketing');"));

        // 测试4：插入子表记录引用已存在的父表id（101）（预期成功）
        System.out.println("\n--> (Expected to SUCCEED) Now inserting the employee with a valid department ID (101).");
        printResult(dbms.processSql("INSERT INTO employees VALUES (1, 'John Doe', 101);"));
        System.out.println("✅ FOREIGN KEY on INSERT is working correctly.");

        // --- 4. 测试删除操作中的外键约束 ---
        System.out.println("\n--- 4. Testing FOREIGN KEY on DELETE ---");
        // 测试1：删除被引用的父表记录（部门101）（预期失败，因为有员工引用）
        System.out.println("--> (Expected to FAIL) Deleting department 101, which is referenced by an employee.");
        printResult(dbms.processSql("DELETE FROM departments WHERE id = 101;"));

        // 测试2：删除未被引用的父表记录（部门102）（预期成功）
        System.out.println("\n--> (Expected to SUCCEED) Deleting department 102, which is NOT referenced.");
        printResult(dbms.processSql("DELETE FROM departments WHERE id = 102;"));

        // 测试3：先删除子表记录（员工1）（预期成功）
        System.out.println("\n--> (Expected to SUCCEED) Deleting the employee first.");
        printResult(dbms.processSql("DELETE FROM employees WHERE emp_id = 1;"));

        // 测试4：再删除父表记录（部门101）（预期成功，此时已无引用）
        System.out.println("\n--> (Expected to SUCCEED) Now deleting department 101, as it is no longer referenced.");
        printResult(dbms.processSql("DELETE FROM departments WHERE id = 101;"));
        System.out.println("✅ FOREIGN KEY on DELETE is working correctly.");

        // --- 5. 最终数据检查：验证表为空 ---
        System.out.println("\n--- 5. Final Data Check ---");
        System.out.println("Departments (should be empty):");
        printResult(dbms.processSql("SELECT * FROM departments;"));
        System.out.println("Employees (should be empty):");
        printResult(dbms.processSql("SELECT * FROM employees;"));

        // 关闭数据库，释放资源
        dbms.shutdown();
        System.out.println("\n============== Foreign Key Functionality Test End ==============");
    }

    /**
     * 辅助方法：格式化并打印QueryResult（SQL执行结果）
     * 简化输出：成功时仅打印关键消息和数据，失败时打印错误信息
     * @param result 待打印的查询结果对象
     */
    private static void printResult(QueryResult result) {
        if (result == null) return; // 空结果直接返回
        if (result.isSuccess) {
            // 成功时：仅在有数据或非默认消息时打印（减少冗余输出）
            if (!result.tuples.isEmpty() || !result.message.contains("Command executed successfully")) {
                System.out.println("SUCCESS: " + result.message.trim());
            }
            // 打印结果集中的所有数据行（若有）
            if (!result.tuples.isEmpty()) {
                result.tuples.forEach(System.out::println);
            }
        } else {
            // 失败时：打印错误信息
            System.err.println("ERROR: " + result.message.trim());
        }
        System.out.println(); // 打印空行分隔不同操作的结果，提升可读性
    }
}